package com.css.fxfzdpzs.modules.czt.service.impl;

import com.css.fxfzdpzs.modules.czt.bo.MapBo;
import com.css.fxfzdpzs.modules.czt.bo.PsCurveBo;
import com.css.fxfzdpzs.modules.czt.constant.DestructiveStateConstant;
import com.css.fxfzdpzs.modules.czt.constant.FimEnum;
import com.css.fxfzdpzs.modules.czt.entity.DestructiveStateEntity;
import com.css.fxfzdpzs.modules.czt.entity.first.*;
import com.css.fxfzdpzs.modules.czt.entity.second.*;
import com.css.fxfzdpzs.modules.czt.param.ProbabilisticEarthquakeParam;
import com.css.fxfzdpzs.modules.czt.vo.*;
import com.css.fxfzdpzs.modules.czt.service.CztService;
import com.css.fxfzdpzs.modules.czt.repository.CztRepository;
import com.css.fxfzdpzs.util.PlatformObjectUtils;
import com.css.fxfzdpzs.util.UUIDGenerator;
import com.css.fxfzdpzs.zcpt.sys.service.SysAreaService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slw.common.helper.PropsHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author y1fan
 * @description
 */
@Slf4j
@Service
public class CztServiceImpl implements CztService {

    @Resource
    private CztRepository cztRepository;

    @Resource
    private RestTemplate restTemplate;

    @Autowired
    private SysAreaService areaService;


    @Override
    public CztMonomerBuildNumVO getBuildNum() {
        CztMonomerBuildNumVO vo = new CztMonomerBuildNumVO();
        List<CztMonomerBuildNum> buildNums = cztRepository.getBuildNum();
        int all = buildNums.stream().mapToInt(CztMonomerBuildNum::getSum).sum();
        Collections.sort(buildNums, (o1, o2) -> o2.getSum().compareTo(o1.getSum()));
        vo.setCztMonomerBuildNums(buildNums);
        vo.setAll(all);
        return vo;
    }

    @Override
    public List<CztProvinceVulnerabilityCount> getVulnerabilityCount() {
        return cztRepository.getVulnerabilityCount();
    }

    @Override
    public CztBeijingVulnerabilityCurveVO getVulnerabilityCurve(String province) {
        List<CztBeijingVulnerabilityCurve> vulnerabilityCurve = cztRepository.getVulnerabilityCurve(province);
        List<CztBeijingVulnerabilityCurve> slight = new ArrayList<>();
        List<CztBeijingVulnerabilityCurve> medium = new ArrayList<>();
        List<CztBeijingVulnerabilityCurve> severity = new ArrayList<>();
        List<CztBeijingVulnerabilityCurve> collapse = new ArrayList<>();

        if (PlatformObjectUtils.isNotEmpty(vulnerabilityCurve)) {
            for (CztBeijingVulnerabilityCurve entity : vulnerabilityCurve) {
                if ("SD".equals(entity.getVulnerabilityType())) {
                    slight.add(entity);
                }
                if ("MD".equals(entity.getVulnerabilityType())) {
                    medium.add(entity);
                }
                if ("ED".equals(entity.getVulnerabilityType())) {
                    severity.add(entity);
                }
                if ("CD".equals(entity.getVulnerabilityType())) {
                    collapse.add(entity);
                }
            }
        }

        CztBeijingVulnerabilityCurveVO vo = new CztBeijingVulnerabilityCurveVO();
        vo.setSlight(slight);
        vo.setCollapse(collapse);
        vo.setMedium(medium);
        vo.setSeverity(severity);
        return vo;
    }

    @Override
    public List<CztSmgcVulnerabilityNum> getVulnerabilityNum() {
        return cztRepository.getVulnerabilityNum();
    }

    @Override
    public Map<String, Object> getBuildVulnerabilityNum() {
        HashMap<String, Object> map = new HashMap<>();
        List<FortificationEntity> list = cztRepository.getAllFortification();
        //总和
        int totalSum = list.stream()
                .mapToInt(FortificationEntity::getSum)
                .sum();

        Map<String, Integer> groupedSums = list.stream()
                .collect(Collectors.groupingBy(
                        FortificationEntity::getFortification,
                        Collectors.summingInt(FortificationEntity::getSum)
                ));

        for (Map.Entry<String, Integer> entry : groupedSums.entrySet()) {
            double percentage = (double) entry.getValue() / totalSum * 100;
            BigDecimal value = BigDecimal.valueOf(percentage).setScale(2, RoundingMode.HALF_UP);
            map.put(entry.getKey(), value);
        }
        return map;
    }

    @Override
    public CztSystemSituationVO getSystemSituation() {
        CztSystemSituationVO vo = new CztSystemSituationVO();
        List<CztSystemSituation> cztSystemSituations = cztRepository.getSystemSituation();
        vo.setCztSystemSituations(cztSystemSituations);
        Integer today = 0;
        Integer all = 0;
        if (PlatformObjectUtils.isNotEmpty(cztSystemSituations)) {
            for (CztSystemSituation cztSystemSituation : cztSystemSituations) {
                today += cztSystemSituation.getVisitsNum();
                all += cztSystemSituation.getAllNum();
            }
        }
        vo.setVisitsTodayNumTimes(today);
        vo.setVisitsAccrueNumTimes(all);
        return vo;
    }

    @Override
    public List<String> getProvince() {
        return cztRepository.getProvince();
    }

    @Override
    public List<DamageGrade> getProportion() {
        return cztRepository.getProportion();
    }

    @Override
    public List<VulnerabilityCompletenessVo> getCompleteness() {
        return cztRepository.getCompleteness();
    }

    @Override
    public Map<String, List<SeismicResistance>> getSeismicResistance(String level) {
        List<SeismicResistance> list = cztRepository.getSeismicResistance(level);
        Map<String, List<SeismicResistance>> map = list.stream().collect(Collectors.groupingBy(SeismicResistance::getDegrees));
        return map;
    }

    @Override
    public PeCurveVo getPsCurve(ProbabilisticEarthquakeParam param) {
        HttpEntity<ProbabilisticEarthquakeParam> entity = new HttpEntity<>(param, buildBaseHeaders());
        PeCurveVo result = null;
        try {
            String url = getBaseUrl("largeScreen/getProbabilisticEarthquake");
            PsCurveBo body = restTemplate.exchange(url, HttpMethod.POST, entity, PsCurveBo.class).getBody();
            result = body.getData();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return result;
    }

    private static HttpHeaders buildBaseHeaders() {
        HttpHeaders headers = new HttpHeaders();
        headers.add("Authorization", "dzzhfxpgyqhxt");
        headers.setContentType(MediaType.APPLICATION_JSON);
        return headers;
    }

    private static String getBaseUrl(String apiUrl) throws Exception {
        Properties configGroup = PropsHelper.loadProps("slw-config.properties");
        String jcsjRestUrl = configGroup.getProperty("ysxRestUrl");
        if (StringUtils.isBlank(jcsjRestUrl)) {
            throw new Exception("配置文件未发现基础数据系统接口URL");
        }
        if (!StringUtils.endsWith(jcsjRestUrl, "/")) {
            jcsjRestUrl += "/";
        }
        return jcsjRestUrl + apiUrl;
    }

    @Override
    public void getDestructiveState() {
        Map<String, Object> param = new HashMap<>();
        HttpEntity<Map<String, Object>> entity = new HttpEntity<>(param, buildBaseHeaders());
        //设置超时时间
        SimpleClientHttpRequestFactory clientHttpRequestFactory = new SimpleClientHttpRequestFactory();
        clientHttpRequestFactory.setConnectTimeout(0);
        clientHttpRequestFactory.setReadTimeout(0);
        restTemplate.setRequestFactory(clientHttpRequestFactory);
        try {
            String url = getBaseUrl("largeScreen/getDestructiveState");
            MapBo body = restTemplate.exchange(url, HttpMethod.GET, entity, MapBo.class).getBody();
            HashMap<String, Object> data = body.getData();
            if (PlatformObjectUtils.isNotEmpty(data)) {
                cztRepository.delState();
                data.forEach((k,v)->{
                    ArrayList<DestructiveStateEntity> list = getMapData(k, v);
                    for (DestructiveStateEntity stateEntity : list) {
                        cztRepository.saveState(stateEntity);
                    }
                });
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private ArrayList<DestructiveStateEntity> getMapData(String key,Object val){
        ArrayList<DestructiveStateEntity> list = new ArrayList<>();
        String intensityStr = "6度,7度,8度,9度,10度";
        String[] region = key.split(",");
        for (String str : intensityStr.split(",")) {
            DestructiveStateEntity stateEntity = new DestructiveStateEntity();
            HashMap<String,Object> map = (HashMap<String, Object>) val;
            HashMap<String,Object> map1 = (HashMap<String, Object>) map.get("基本完好");
            HashMap<String,Object> map2 = (HashMap<String, Object>)map.get("轻微破坏");
            HashMap<String,Object> map3 = (HashMap<String, Object>)map.get("中等破坏");
            HashMap<String,Object> map4 = (HashMap<String, Object>)map.get("严重破坏");
            HashMap<String,Object> map5 = (HashMap<String, Object>)map.get("倒塌");
            stateEntity.setId(UUIDGenerator.getUUID());
            stateEntity.setProvince(region[0]);
            stateEntity.setProvinceCode(region[1]);
            stateEntity.setCountyName(region[2]);
            stateEntity.setCountyCode(region[3]);
            stateEntity.setIntensity(str);
            stateEntity.setBasically(new BigDecimal(map1.get(DestructiveStateConstant.getConstant1(intensityStr,0)).toString()));
            stateEntity.setBasicallyPercentage(new BigDecimal(map1.get(DestructiveStateConstant.getConstant1(intensityStr,1)).toString()));
            stateEntity.setMinor(new BigDecimal(map2.get(DestructiveStateConstant.getConstant1(intensityStr,0)).toString()));
            stateEntity.setMinorPercentage(new BigDecimal(map2.get(DestructiveStateConstant.getConstant1(intensityStr,1)).toString()));
            stateEntity.setModerate(new BigDecimal(map3.get(DestructiveStateConstant.getConstant1(intensityStr,0)).toString()));
            stateEntity.setModeratePercentage(new BigDecimal(map3.get(DestructiveStateConstant.getConstant1(intensityStr,1)).toString()));
            stateEntity.setSerious(new BigDecimal(map4.get(DestructiveStateConstant.getConstant1(intensityStr,0)).toString()));
            stateEntity.setSeriousPercentage(new BigDecimal(map4.get(DestructiveStateConstant.getConstant1(intensityStr,1)).toString()));
            stateEntity.setCollapse(new BigDecimal(map5.get(DestructiveStateConstant.getConstant1(intensityStr,0)).toString()));
            stateEntity.setCollapsePercentage(new BigDecimal(map5.get(DestructiveStateConstant.getConstant1(intensityStr,1)).toString()));
            list.add(stateEntity);
        }
        return list;
    }

    @Override
    public List<DestructiveStateVo> seismicResistance() {
        return cztRepository.seismicResistance();
    }

    @Override
    public HashMap<String, Object> getCurve() {
        List<DestructiveStateEntity> list = cztRepository.getAllState();
        HashMap<String, Object> map = new HashMap<>();
        if (PlatformObjectUtils.isNotEmpty(list)) {
            //根据省分组
            Map<String, List<DestructiveStateEntity>> collect = list.stream().collect(Collectors.groupingBy(DestructiveStateEntity::getProvince));
            collect.forEach((k, v) -> {
                Map<String, List<DestructiveStateEntity>> intensityCollect = v.stream().collect(Collectors.groupingBy(DestructiveStateEntity::getIntensity));
                ArrayList<MatrixVo> matrixList = new ArrayList<>();
                intensityCollect.forEach((key, val) -> {
                    MatrixVo matrixVo = new MatrixVo();
                    BigDecimal basically = BigDecimal.ZERO;
                    BigDecimal minor = BigDecimal.ZERO;
                    BigDecimal moderate = BigDecimal.ZERO;
                    BigDecimal serious = BigDecimal.ZERO;
                    BigDecimal collapse = BigDecimal.ZERO;
                    for (DestructiveStateEntity item : val) {
                        basically = basically.add(item.getBasically());
                        minor = minor.add(item.getMinor());
                        moderate = moderate.add(item.getModerate());
                        serious = serious.add(item.getSerious());
                        collapse = collapse.add(item.getCollapse());
                    }
                    matrixVo.setIntensity(key);
                    matrixVo.setBasically(basically);
                    matrixVo.setMinor(minor);
                    matrixVo.setModerate(moderate);
                    matrixVo.setSerious(serious);
                    matrixVo.setCollapse(collapse);
                    matrixList.add(matrixVo);
                });
                map.put(k, turningCurve(matrixList));
            });
        }
        return map;
    }

    /**
     * 矩阵转曲线
     *
     * @param dataList
     * @return
     */
    public static List<CurveVo> turningCurve(List<MatrixVo> dataList) {
        ArrayList<CurveVo> resultList = new ArrayList<>();
        Map<String, List<MatrixVo>> collect = dataList.stream().collect(Collectors.groupingBy(MatrixVo::getIntensity));
        collect.forEach((k, v) -> {
            for (MatrixVo entity : v) {
                CurveVo cVo = new CurveVo();
                cVo.setBreakState("CD");
                cVo.setIm(FimEnum.getByCode(entity.getIntensity()));
                cVo.setFim(entity.getCollapse().divide(new BigDecimal("100").setScale(6, RoundingMode.HALF_UP)));
                resultList.add(cVo);
                CurveVo edVo = new CurveVo();
                edVo.setBreakState("ED");
                edVo.setIm(FimEnum.getByCode(entity.getIntensity()));
                BigDecimal fim = entity.getCollapse().add(entity.getSerious());
                edVo.setFim(fim.divide(new BigDecimal("100")).setScale(6, RoundingMode.HALF_UP));
                resultList.add(edVo);
                CurveVo mdVo = new CurveVo();
                mdVo.setBreakState("MD");
                mdVo.setIm(FimEnum.getByCode(entity.getIntensity()));
                BigDecimal mdFim = entity.getCollapse().add(entity.getSerious()).add(entity.getModerate());
                mdVo.setFim(mdFim.divide(new BigDecimal("100")).setScale(6, RoundingMode.HALF_UP));
                resultList.add(mdVo);
                CurveVo sdVo = new CurveVo();
                sdVo.setBreakState("SD");
                sdVo.setIm(FimEnum.getByCode(entity.getIntensity()));
                BigDecimal sdFim = entity.getCollapse().add(entity.getSerious()).add(entity.getModerate()).add(entity.getMinor());
                sdVo.setFim(sdFim.divide(new BigDecimal("100")).setScale(6, RoundingMode.HALF_UP));
                resultList.add(sdVo);
            }
        });
        return resultList;
    }

    @Override
    public HashMap<String, Object> ysxComplete() {
        HashMap<String, Object> map = new HashMap<>();
        List<DestructiveStateEntity> list = cztRepository.getAllState();
        Map<String, List<DestructiveStateEntity>> collect = list.stream().collect(Collectors.groupingBy(DestructiveStateEntity::getProvince));
        collect.forEach((k, v) -> {
            Map<String, Long> stateCount = new HashMap<>();
            stateCount.put("基本完好", 0L);
            stateCount.put("轻微破坏", 0L);
            stateCount.put("中等破坏", 0L);
            stateCount.put("严重破坏", 0L);
            stateCount.put("毁坏", 0L);
            Map<String, Long> countedStates = v.stream()
                    .collect(Collectors.groupingBy(DestructiveStateEntity::getDestructiveState, Collectors.counting()));
            stateCount.putAll(countedStates);
            map.put(k, stateCount);
        });
        return map;
    }
}



